Skip to content

fix: migrate to pi-sidecar and improve AI cherry-pick conflict resolution#1127

Merged
myakove merged 13 commits into
mainfrom
fix/issue-1126-pi-sidecar-ai-cherry-pick
Jun 23, 2026
Merged

fix: migrate to pi-sidecar and improve AI cherry-pick conflict resolution#1127
myakove merged 13 commits into
mainfrom
fix/issue-1126-pi-sidecar-ai-cherry-pick

Conversation

@myakove

@myakove myakove commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator
  • Replace ai-cli-runner with pi-sidecar-client
  • Add sidecar-helper/ for Docker multi-stage build
  • Create entrypoint.sh with lifecycle coupling (trap + monitor + readiness)
  • Enhance cherry-pick prompt with commit context and resolution rules
  • Add post-resolution scope verification
  • Update tests and documentation

Closes #1126

@myakove-bot

Copy link
Copy Markdown
Collaborator

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: Disabled for this repository
  • Pre-commit Checks: pre-commit runs automatically if .pre-commit-config.yaml exists
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified
  • Labels: All label categories are enabled (default configuration)

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)
  • /regenerate-welcome - Regenerate this welcome message
  • /security-override - Set security check runs to pass (maintainers only)
  • /security-override cancel - Re-run security checks

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest python-module-install - Test Python package installation
  • /retest pre-commit - Run pre-commit hooks and checks
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3
  • /cherry-pick-retry <branch> - Retry a failed cherry-pick (merged PRs only)

Branch Management

  • /rebase - Rebase this PR branch onto its base branch

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. LGTM Count: Minimum 1 /lgtm from reviewers
  3. Status Checks: All required status checks must pass
  4. No Blockers: No wip, hold, has-conflicts labels and PR must be mergeable (no conflicts)
  5. Verified: PR must be marked as verified

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove
  • rnetser

Reviewers:

  • myakove
  • rnetser
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge
AI Features
  • Conventional Title: Mode: fix (claude/claude-opus-4-6[1m])
  • Cherry-Pick Conflict Resolution: Enabled (claude/claude-opus-4-6[1m])
  • Test Oracle: Triggers: approved (claude/claude-opus-4-6[1m]); /test-oracle can be used anytime
Security Checks
  • Suspicious Path Detection: Monitors paths: .claude/, .vscode/, .cursor/, .devcontainer/, .pi/, .github/workflows/, .github/actions/
  • Committer Identity Check: Verifies last committer matches PR author
  • Mandatory: Security checks block merge (use /security-override to bypass — maintainers only)

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is removed on new commits unless the push is detected as a clean rebase
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Migrate AI integration to pi-sidecar and harden AI cherry-pick conflict resolution
🐞 Bug fix ✨ Enhancement ⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

Description

• Replace ai-cli-runner integration with pi-sidecar-client for AI calls
• Add Node sidecar-helper and container entrypoint to run/monitor the pi-sidecar
• Improve AI cherry-pick prompts with commit context and add post-resolution scope checks
Diagram

graph TD
  HC["Docker healthcheck"] --> WH["Webhook server (Python)"]
  HC --> SC["Pi sidecar (Node)"]
  EP["entrypoint.sh"] --> SC --> AP["AI providers (Vertex/Claude/etc)"]
  EP --> WH --> PC["pi-sidecar-client"] --> SC
  WH --> GIT["Git worktree"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Run sidecar as a separate container/service
  • ➕ Clear process separation; avoids PID 1 coupling and bash monitoring logic
  • ➕ Independent scaling/restarts; cleaner health and logs per component
  • ➖ More deployment complexity (compose/k8s service wiring, networking, auth/env distribution)
  • ➖ Harder local/dev parity if single-container is a requirement
2. Use a process supervisor (s6-overlay/supervisord) instead of custom entrypoint.sh
  • ➕ More robust lifecycle management, signal handling, and restart policies
  • ➕ Less bespoke bash to maintain and fewer edge cases around traps
  • ➖ Adds another dependency and operational surface area
  • ➖ May be heavier than needed for a single auxiliary process
3. Prebuild/publish sidecar-helper artifact and copy it in (no Node build stage)
  • ➕ Faster Docker builds; fewer moving parts in CI
  • ➕ Reduces supply-chain/build-time risk in the main image
  • ➖ Requires artifact/version management and release discipline
  • ➖ Harder to iterate quickly when sidecar wrapper changes

Recommendation: The chosen approach (multi-stage Node build + in-container sidecar started by entrypoint.sh) is reasonable if a single container is required and you want tightly coupled health/reliability. If operational stability becomes a recurring concern, consider switching to a lightweight supervisor to reduce custom lifecycle/bash logic while keeping the single-container model.

Files changed (11) +446 / -103

Enhancement (2) +17 / -12
server.tsStart the pi-sidecar server +3/-0

Start the pi-sidecar server

• Implements the minimal TypeScript entrypoint that imports and runs startSidecar() to expose the sidecar service (including /health).

sidecar-helper/src/server.ts

ai_cli.pyReplace AI CLI wrapper with pi-sidecar call_ai() API +14/-12

Replace AI CLI wrapper with pi-sidecar call_ai() API

• Refactors the shared AI wrapper to use pi_sidecar_client.call_ai_once and return a structured AIResult. Renames the public function from call_ai_cli to call_ai and adds support for system_prompt and tool hints.

webhook_server/libs/ai_cli.py

Bug fix (1) +147 / -42
runner_handler.pyImprove AI prompts, add commit context, and verify cherry-pick scope +147/-42

Improve AI prompts, add commit context, and verify cherry-pick scope

• Migrates conventional-title and cherry-pick AI calls to call_ai() and AIResult handling. Enhances cherry-pick prompts with commit hash, message, target branch, and original diff stat; passes a dedicated system prompt and tool set. Adds post-resolution verification comparing original vs resulting file-change counts and logs warnings when scope appears reduced.

webhook_server/libs/handlers/runner_handler.py

Tests (1) +171 / -43
test_runner_handler.pyUpdate mocks for AIResult and add verification tests +171/-43

Update mocks for AIResult and add verification tests

• Updates unit tests to mock call_ai() and AIResult instead of tuple-based call_ai_cli results. Adds coverage ensuring commit_hash/target_branch are passed to AI resolution and that post-resolution scope verification logs a warning when the cherry-picked change set shrinks.

webhook_server/tests/test_runner_handler.py

Documentation (2) +27 / -3
CLAUDE.mdDocument pi-sidecar usage and cherry-pick scope verification +26/-2

Document pi-sidecar usage and cherry-pick scope verification

• Updates AI feature documentation to reflect pi-sidecar integration and new terminology. Adds sidecar architecture notes, required environment variables, startup sequence, and dual healthcheck behavior, plus describes post-resolution scope verification for cherry-picks.

CLAUDE.md

schema.yamlFix AI model identifier example in schema docs +1/-1

Fix AI model identifier example in schema docs

• Adjusts the example model identifier formatting (notably the 1m suffix) to match the expected naming convention.

webhook_server/config/schema.yaml

Other (5) +84 / -3
DockerfileAdd multi-stage Node build and run sidecar via entrypoint.sh +19/-2

Add multi-stage Node build and run sidecar via entrypoint.sh

• Introduces a Node-based build stage to compile the sidecar-helper TypeScript and copy only production artifacts into the final image. Exposes the sidecar port, switches ENTRYPOINT to a new bash script, and expands HEALTHCHECK to validate both webhook server and sidecar endpoints.

Dockerfile

entrypoint.shStart/monitor pi-sidecar and gate startup on readiness +32/-0

Start/monitor pi-sidecar and gate startup on readiness

• Adds a PID-coupled startup script that launches the sidecar in the background, traps exit to clean it up, kills PID 1 if the sidecar dies unexpectedly, and waits up to 15s for /health before exec-ing the Python entrypoint.

entrypoint.sh

pyproject.tomlSwap ai-cli-runner for pi-sidecar-client dependency +1/-1

Swap ai-cli-runner for pi-sidecar-client dependency

• Replaces the Python dependency used for AI calls, moving from ai-cli-runner to pi-sidecar-client to route requests through the sidecar.

pyproject.toml

package.jsonIntroduce Node sidecar-helper package for pi-sidecar +17/-0

Introduce Node sidecar-helper package for pi-sidecar

• Adds a minimal Node package definition with a build/start script and a runtime dependency on @myk-org/pi-sidecar, plus TypeScript tooling as dev dependencies.

sidecar-helper/package.json

tsconfig.jsonConfigure TypeScript build output for sidecar-helper +15/-0

Configure TypeScript build output for sidecar-helper

• Adds a strict TS configuration targeting ES2022 with NodeNext modules, producing compiled output in dist/ from src/.

sidecar-helper/tsconfig.json

@qodo-code-review

qodo-code-review Bot commented Jun 20, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (17) 📘 Rule violations (2) 📎 Requirement gaps (5) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 24 rules

Grey Divider


Action required

1. _resolve_cherry_pick_with_ai prompt vague 📎 Requirement gap ⚙ Maintainability
Description
The updated AI cherry-pick prompt no longer provides explicit rules to preserve ALL cherry-picked
changes and limit edits to compatibility-only changes, nor does it describe how to handle key
conflict types. This can lead to AI resolutions that drop or incorrectly alter intended changes,
violating the required preservation guidance.
Code

webhook_server/libs/handlers/runner_handler.py[R1285-1299]

+        system_prompt = (
+            "You are an expert software engineer. Resolve git cherry-pick merge conflicts "
+            "preserving the intent of the original commit."
+        )

        prompt = (
-            "You are in a git repository with cherry-pick merge conflicts. "
-            "Resolve ALL conflicts in ALL files.\n\n"
-            "How to handle each conflict type:\n"
-            "- Standard conflict markers (<<<<<<< HEAD, =======, >>>>>>>): "
-            "HEAD is the target branch. Adapt the cherry-picked changes to fit "
-            "the target branch code.\n"
-            "- File 'deleted in HEAD and modified in <commit>': This means the file "
-            "does not exist on the target branch. If the cherry-pick is introducing "
-            "this file to the target branch, keep the file and 'git add' it. "
-            "If the file was intentionally removed from the target branch and the "
-            "changes are not relevant, 'git rm' it.\n"
-            "- File 'added in both' or 'renamed': Merge the content, keeping both "
-            "sides' intent.\n\n"
-            "After resolving all conflicts, stage everything with 'git add' and "
-            "make sure the result is syntactically valid."
+            "This repository has cherry-pick merge conflicts that need to be resolved.\n\n"
+            f"**Original commit:** `{commit_hash}`\n"
+            f"**Commit message:** {commit_message}\n"
+            f"**Cherry-picking onto branch:** `{target_branch}`\n"
+            f"**PR title:** {pr_title}\n\n"
+            f"**Files changed in original commit:**\n```\n{commit_diff_stat}\n```\n\n"
+            "Resolve all conflicts. The goal is to apply the original commit's changes "
+            "onto the target branch. Use the available tools to inspect the original commit "
+            "diff, read the conflicted files, and edit them to resolve conflicts."
Relevance

⭐⭐⭐ High

Team previously added explicit conflict-type guidance to AI cherry-pick prompt and tests in PR
#1046; likely enforced.

PR-#1046

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 181409 requires explicit preservation and conflict-type guidance in the
conflict-resolution prompt. The prompt text in runner_handler.py only instructs to resolve
conflicts and "apply the original commit's changes" / "preserving the intent" without explicit
preservation/compatibility-only rules or conflict-type handling instructions.

Replace vague 'adapt' guidance with explicit rules to preserve cherry-picked changes
webhook_server/libs/handlers/runner_handler.py[1285-1299]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`_resolve_cherry_pick_with_ai()`'s `system_prompt`/`prompt` is missing the explicit preservation and conflict-type rules required to prevent the AI from dropping cherry-picked changes.

## Issue Context
The compliance requirement expects the prompt to state: preserve ALL cherry-picked changes, only modify what is necessary for compatibility with the target branch, and give explicit handling guidance for common conflict types.

## Fix Focus Areas
- webhook_server/libs/handlers/runner_handler.py[1285-1299]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. handle_tool_request catches Exception ✓ Resolved 📘 Rule violation ≡ Correctness
Description
handle_tool_request() wraps await request.json() in a broad except Exception, which can
silently convert unexpected programming/runtime errors into a 400 response. This violates the
requirement to catch specific exception types instead of broad Exception in non-terminal code
paths.
Code

webhook_server/web/tool_server.py[R66-71]

+async def handle_tool_request(request: web.Request) -> web.Response:
+    """Execute a registered tool."""
+    try:
+        data: dict[str, Any] = await request.json()
+    except Exception:
+        return web.json_response({"detail": "Invalid JSON"}, status=400)
Relevance

⭐⭐⭐ High

Team prefers not swallowing broad exceptions; accepted “don’t swallow exceptions” guidance in PR
#1114.

PR-#1114
PR-#982

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 181390 requires catching specific exception types instead of broad Exception. The
code at webhook_server/web/tool_server.py[66-71] catches all exceptions when parsing JSON, which
can suppress non-JSON-related errors and misclassify them as invalid input.

Rule 181390: Catch specific exception types instead of broad Exception
webhook_server/web/tool_server.py[66-71]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`handle_tool_request()` uses `except Exception` around `await request.json()`, which can mask unexpected failures by returning a 400 error.

## Issue Context
This endpoint is used by AI custom tools; hiding unexpected exceptions can make real regressions hard to detect and troubleshoot.

## Fix Focus Areas
- webhook_server/web/tool_server.py[66-71]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Blocked flag bypass ✓ Resolved 🐞 Bug ⛨ Security
Description
run_git_command() only blocks flags when a token exactly equals a blocked flag, so
--output=/tmp/x (and similar --flag=value forms) bypass the check. This can re-enable git
options that write files, breaking the endpoint’s intended read-only safety contract for AI tooling.
Code

webhook_server/web/git_tools.py[R70-75]

+    for part in parts[1:]:
+        if part in BLOCKED_FLAGS:
+            raise HTTPException(
+                status_code=403,
+                detail=f"Git flag '{part}' not allowed for security reasons",
+            )
Relevance

⭐⭐⭐ High

Team repeatedly accepts security hardening around command parsing/injection (e.g., env-prefix exec
bug fixed in PR #1024).

PR-#1024
PR-#1107
PR-#1117

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The endpoint defines BLOCKED_FLAGS (including --output) but only checks `if part in
BLOCKED_FLAGS, which will not match tokens like --output=/tmp/x produced by shlex.split()`. That
makes the blocked list ineffective for common --flag=value usage.

webhook_server/web/git_tools.py[21-22]
webhook_server/web/git_tools.py[70-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`webhook_server/web/git_tools.py::run_git_command()` blocks dangerous flags using exact token matching (`if part in BLOCKED_FLAGS`). This is bypassable when git flags are supplied in `--flag=value` form (e.g., `--output=/tmp/x`), which can allow writing output to arbitrary paths and violates the intended read-only safety boundary.

## Issue Context
- `BLOCKED_FLAGS` includes `--output`, but `shlex.split()` will produce a single token like `--output=/tmp/x`, which does not equal `--output`.
- The endpoint is explicitly designed as a constrained tool surface for the AI sidecar, so bypasses here matter even though it’s localhost-only.

## Fix Focus Areas
- webhook_server/web/git_tools.py[21-22]
- webhook_server/web/git_tools.py[70-75]

## Suggested fix
- Update the blocked-flag check to reject both:
 - exact matches: `part == flag`
 - assignment forms: `part.startswith(flag + "=")`
- (Optional hardening) Consider normalizing/validating allowed flags per subcommand instead of a small blocked list, to reduce future bypass risk.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (13)
4. Localhost check fails open 🐞 Bug ⛨ Security
Description
LocalhostOnlyMiddleware only enforces loopback when request.client is present and explicitly allows
non-IP client hosts, so /internal/* routes can be reached without a verified localhost source in
some ASGI/proxy/test setups. This weakens the intended protection for the internal git-tools
endpoint.
Code

webhook_server/web/git_tools.py[R30-38]

+    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
+        if request.url.path.startswith("/internal/") and request.client:
+            client_host = request.client.host
+            try:
+                ip = ipaddress.ip_address(client_host)
+                if not ip.is_loopback:
+                    return JSONResponse(status_code=403, content={"detail": "Internal endpoints are localhost-only"})
+            except ValueError:
+                pass  # Non-IP host (e.g., test client) — allow
Relevance

⭐⭐⭐ High

Team often tightens security gates (e.g., add trusted-network deps, fail-safe bot-ownership checks)
— likely accept fail-closed localhost check.

PR-#982
PR-#1108

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The middleware currently gates on and request.client and treats non-IP hosts as allowed, which
means the localhost restriction is not enforced when client info is unavailable or unparsable.
Another security dependency in app.py demonstrates the codebase expects request.client/IP parsing
to fail and denies in that situation, supporting that this should fail closed here too.

webhook_server/web/git_tools.py[1-7]
webhook_server/web/git_tools.py[27-39]
webhook_server/app.py[117-133]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`LocalhostOnlyMiddleware` is intended to make `/internal/*` endpoints localhost-only, but it currently fails open in two cases:
1) when `request.client` is missing, and
2) when `request.client.host` is not parseable as an IP (`ValueError`), where it currently allows the request.

This can allow access to internal endpoints without a verified loopback source.

### Issue Context
The module docstring claims the endpoints are “Bound to 127.0.0.1 only”, and other security checks in the codebase (e.g., `require_trusted_network`) deny access when the client IP is missing/invalid. For consistency and safety, the internal middleware should also fail closed.

### Fix Focus Areas
- webhook_server/web/git_tools.py[30-39]

### Suggested change
- If the request path starts with `/internal/` and `request.client` is missing, return 403.
- If `ipaddress.ip_address(client_host)` raises `ValueError`, return 403 (or explicitly allow only known-safe test values behind a test-only flag).
- Optionally add a small log message when denying due to missing/invalid client IP to aid debugging in unusual deployments.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. call_ai() lacks sidecar healthcheck ✓ Resolved 📎 Requirement gap ☼ Reliability
Description
call_ai() calls pi_sidecar_client.call_ai_once directly without checking that the pi-sidecar
server is reachable/healthy first. This can cause opaque runtime failures when the sidecar is
unavailable, instead of failing with a clear availability error as required.
Code

webhook_server/libs/ai_cli.py[R10-34]

+async def call_ai(
    prompt: str,
    ai_provider: str,
    ai_model: str,
    cwd: str,
-    cli_flags: list[str] | None = None,
    timeout_minutes: int | None = None,
-) -> tuple[bool, str]:
-    """Call an AI CLI tool. Thin wrapper around ai_cli_runner.call_ai_cli.
+    system_prompt: str = "",
+    tools: list[str] | None = None,
+    custom_tools: list[dict[str, Any]] | None = None,
+) -> AIResult:
+    """Call an AI provider via pi-sidecar. Thin wrapper around pi_sidecar_client.call_ai_once.

-    Accepts cwd as str (matching clone_repo_dir type) and converts to Path.
+    Returns:
+        AIResult with .success, .text, and .error attributes.
    """
-    return await _call_ai_cli(
+    return await call_ai_once(
        prompt=prompt,
        ai_provider=ai_provider,
        ai_model=ai_model,
-        cwd=Path(cwd),
-        cli_flags=cli_flags,
-        ai_cli_timeout=timeout_minutes,
+        cwd=cwd,
+        ai_call_timeout=timeout_minutes,
+        system_prompt=system_prompt,
+        tools=tools,
+        custom_tools=custom_tools,
    )
Relevance

⭐⭐⭐ High

Team previously added preflight health check before external AI service calls (test-oracle) in PR
#1002.

PR-#1002

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 181407 requires an availability/health check prior to invoking AI. The new
call_ai() wrapper directly invokes call_ai_once(...) with no preflight health check or explicit
unavailable-sidecar error handling.

Ensure deployment starts/has access to pi-sidecar server before AI calls
webhook_server/libs/ai_cli.py[10-34]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`webhook_server/libs/ai_cli.py:call_ai()` calls pi-sidecar directly but does not perform any explicit availability/health check before issuing AI requests.

## Issue Context
Compliance requires the application to verify that the pi-sidecar server is started/reachable before AI calls, and to fail with a clear error when it is not.

## Fix Focus Areas
- webhook_server/libs/ai_cli.py[10-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Title regex truncates suggestion ✓ Resolved 🐞 Bug ≡ Correctness
Description
In _get_ai_title_suggestion(), the non-wildcard regex captures only the conventional commit type
(e.g., "fix") but not the full title (e.g., "fix: ..."), because only the allowed-types alternation
is wrapped in the capture group. This can cause the check to return an invalid suggestion even when
the AI response contains a valid conventional title.
Code

webhook_server/libs/handlers/runner_handler.py[R992-1001]

+                    if is_wildcard or not allowed_names:
+                        # Wildcard mode: match any word followed by optional scope and colon
+                        title_pattern = r"(?:^|\n|[.!?]\s*)(\w+(?:\([^)]*\))?!?:\s*\S.+)"
+                    else:
+                        allowed_types_pattern = "|".join(re.escape(name) for name in allowed_names)
+                        title_pattern = rf"(?:^|\n|[.!?]\s*)({allowed_types_pattern})(?:\([^)]*\))?!?:\s*\S.+"
+                    match = re.search(title_pattern, response_text, re.IGNORECASE)
+                    if match:
+                        suggestion = match.group(1).strip().strip("`").strip('"').strip("'")
+                    else:
Relevance

⭐⭐⭐ High

Team frequently accepts correctness fixes in runner_handler regex/title logic (e.g.,
conventional-title regex updates merged).

PR-#900
PR-#1080

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The pattern in the non-wildcard path captures only ({allowed_types_pattern}), but the code returns
match.group(1), so the suggestion becomes only the type token instead of the full title line.

webhook_server/libs/handlers/runner_handler.py[988-1004]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`_get_ai_title_suggestion()` uses `match.group(1)` as the suggestion. In the non-wildcard branch, the capture group only wraps the allowed type token, so the returned suggestion is just the type (e.g., `fix`) instead of the full conventional title line (e.g., `fix: correct the title`).

### Issue Context
This logic runs when AI title suggestions are enabled and `allowed_names` is non-empty.

### Fix Focus Areas
- webhook_server/libs/handlers/runner_handler.py[992-1004]

### Suggested fix
Update the non-wildcard `title_pattern` so the *entire* conventional-title string is captured in group(1), e.g.:
- `title_pattern = rf"(?:^|\n|[.!?]\s*)({allowed_types_pattern}(?:\([^)]*\))?!?:\s*\S.+)"`

Keep `suggestion = match.group(1)...` as-is after the regex fix.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Async subprocess mock breaks tests ✓ Resolved 🐞 Bug ≡ Correctness
Description
test_git_tools patches asyncio.create_subprocess_shell with a non-awaitable mock, but
run_git_command() awaits it, which will raise a TypeError and break the new test suite. This
makes the added coverage unreliable and can fail CI on this PR.
Code

webhook_server/tests/test_git_tools.py[R21-27]

+    def test_allowed_command_diff(self, client: TestClient) -> None:
+        with patch("webhook_server.web.git_tools.asyncio.create_subprocess_shell") as mock_proc:
+            process = AsyncMock()
+            process.communicate.return_value = (b"file.py | 2 +-\n", b"")
+            process.returncode = 0
+            mock_proc.return_value = process
+
Relevance

⭐⭐⭐ High

Similar async-test mock awaitability fixes were accepted before (patch non-awaitable causing
TypeError) in PR #906.

PR-#906

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The endpoint awaits asyncio.create_subprocess_shell, but the tests patch it without
new_callable=AsyncMock, so the patched symbol will not be awaitable and the await will fail.

webhook_server/web/git_tools.py[32-55]
webhook_server/tests/test_git_tools.py[21-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`run_git_command()` does `proc = await asyncio.create_subprocess_shell(...)`, but the tests patch `create_subprocess_shell` using the default (sync) mock, which is not awaitable. This will fail when the endpoint code awaits the patched function.

### Issue Context
The new tests in `webhook_server/tests/test_git_tools.py` repeatedly use:
```py
with patch("...asyncio.create_subprocess_shell") as mock_proc:
   mock_proc.return_value = process
```
This should instead patch the coroutine with an `AsyncMock` so `await asyncio.create_subprocess_shell(...)` returns the mocked process.

### Fix Focus Areas
- webhook_server/tests/test_git_tools.py[21-80]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Internal git-tools exposed ✓ Resolved 🐞 Bug ⛨ Security
Description
The /internal/git-tools router is added to the main FastAPI app without any access control, and
the server defaults to binding on 0.0.0.0, so this “internal” endpoint can be reachable off-host
if the service port is published.
Code

webhook_server/app.py[R301-302]

FASTAPI_APP: FastAPI = FastAPI(title="webhook-server", lifespan=lifespan)
+FASTAPI_APP.include_router(git_tools_router)
Relevance

⭐⭐⭐ High

Team often gates risky FastAPI endpoints via env/deps (ENABLE_LOG/MCP, require_trusted_network).
Unconditional internal router likely changed.

PR-#844
PR-#916
PR-#982

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The router is included unconditionally in the app, and the process entrypoint shows the server binds
to 0.0.0.0 by default, so the endpoint is not inherently localhost-only.

webhook_server/app.py[55-56]
webhook_server/app.py[300-303]
entrypoint.py[13-17]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`/internal/git-tools/run` is mounted into the public FastAPI app and currently has no enforcement that requests originate from localhost, despite being documented as “Bound to 127.0.0.1 only”. This can make the endpoint accessible to external callers depending on deployment/networking.

### Issue Context
The server’s default bind address is `0.0.0.0`, which listens on all interfaces.

### Fix Focus Areas
- webhook_server/app.py[300-303]
- webhook_server/web/git_tools.py[19-45]

### Implementation guidance
Choose one (or combine):
- Add a dependency / middleware for the `/internal/*` router that rejects any request whose `request.client.host` is not `127.0.0.1` / `::1`.
- Alternatively require a shared secret header (set in container env) and validate it in the endpoint/dependency.
- Update/adjust tests to set an allowed client host when using `TestClient`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Prompt missing PR title 📎 Requirement gap ☼ Reliability
Description
The updated cherry-pick conflict-resolution prompt includes commit context and target branch but
does not include the original PR title (pull_request.title) as required. Missing this context can
reduce resolution quality and increase semantically incorrect conflict fixes.
Code

webhook_server/libs/handlers/runner_handler.py[R1229-1236]

        prompt = (
            "You are in a git repository with cherry-pick merge conflicts. "
            "Resolve ALL conflicts in ALL files.\n\n"
-            "How to handle each conflict type:\n"
+            f"## Original Commit Context\n"
+            f"**Commit:** `{commit_hash}`\n"
+            f"**Message:** {commit_message}\n"
+            f"**Target branch:** `{target_branch}`\n\n"
+            f"**Original commit changed files:**\n```\n{commit_diff_stat}\n```\n\n"
Relevance

⭐⭐⭐ High

Team accepts adding missing AI prompt context; they previously added base-branch context to AI
prompts in PR #1080.

PR-#1080
PR-#1025

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance ID 181410 requires the conflict-resolution prompt to include the original PR title and
target branch. The prompt currently includes commit_hash, commit_message, and target_branch,
but contains no PR title context.

Improve conflict-resolution prompt with original commit and PR/branch context
webhook_server/libs/handlers/runner_handler.py[1229-1236]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The cherry-pick conflict-resolution AI prompt is required to include the original PR title (`pull_request.title`), but the current prompt only includes commit hash/message and target branch.

## Issue Context
Compliance ID 181410 requires adding original PR title and target branch context to reduce incorrect AI resolutions.

## Fix Focus Areas
- webhook_server/libs/handlers/runner_handler.py[1160-1271]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Prompt missing diff verification 📎 Requirement gap ☼ Reliability
Description
The cherry-pick conflict-resolution prompt instructs the AI to view the original commit diff, but
does not instruct comparing the resolved state against that original diff. This violates the
requirement to explicitly verify the resolution preserved the original intent.
Code

webhook_server/libs/handlers/runner_handler.py[R1237-1245]

+            "## Instructions\n\n"
+            f"Run `git log --oneline -1 {commit_hash}` to understand the original intent.\n"
+            f"Run `git diff {commit_hash}^..{commit_hash}` to see the original changes.\n\n"
+            "### Conflict Resolution Rules\n"
+            "- **Prefer the cherry-picked changes.** Only use HEAD (target branch) when "
+            "the cherry-picked code references APIs/functions that don't exist on the target branch.\n"
            "- Standard conflict markers (<<<<<<< HEAD, =======, >>>>>>>): "
-            "HEAD is the target branch. Adapt the cherry-picked changes to fit "
-            "the target branch code.\n"
+            "HEAD is the target branch. Resolve in favor of the cherry-picked changes "
+            "unless they reference code not present on the target branch.\n"
Relevance

⭐⭐⭐ High

Team has repeatedly merged stronger AI cherry-pick guidance/verification behavior; prompt
improvements landed in PR #1046.

PR-#1046
PR-#1025

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance ID 181412 requires an explicit prompt instruction to compare the resolved result against
the original commit diff. The current prompt only instructs running `git diff
{commit_hash}^..{commit_hash}` to view original changes, but does not instruct comparing the
post-resolution state to that diff.

Add AI instruction to verify resolution against original diff
webhook_server/libs/handlers/runner_handler.py[1237-1245]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The AI prompt lacks an explicit instruction to compare the final resolved/staged changes against the original commit diff to ensure no intended changes were dropped.

## Issue Context
Compliance ID 181412 requires adding a prompt instruction to verify the resolution against the original diff (e.g., compare resolved changes vs `git diff {commit_hash}^..{commit_hash}`).

## Fix Focus Areas
- webhook_server/libs/handlers/runner_handler.py[1237-1256]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. New files not staged 🐞 Bug ≡ Correctness
Description
After AI resolves conflicts, _resolve_cherry_pick_with_ai() runs git add -u, which does not
stage newly-added/untracked files. This can make cherry-pick --continue fail or produce a
cherry-pick commit that silently omits files introduced by the cherry-picked change.
Code

↗ webhook_server/libs/handlers/runner_handler.py

            )
Relevance

⭐⭐⭐ High

Team previously staged all changes with git add -A in cherry-pick automation; similar staging
robustness accepted in PR #1108.

PR-#1108

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The AI resolution finalization stages with git add -u, while the same cherry-pick flow later uses
git add -A to ensure all modifications (including new files) are staged for pre-commit auto-fix
commits—highlighting that -A is the expected behavior when you must not miss new files.

webhook_server/libs/handlers/runner_handler.py[1280-1310]
webhook_server/libs/handlers/runner_handler.py[1597-1604]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
After AI conflict resolution, the code stages changes with `git add -u`, which does not include newly-added files. This can break cherry-pick continuation and/or drop new files from the resulting commit.

### Issue Context
This occurs in `RunnerHandler._resolve_cherry_pick_with_ai()` right before the CHERRY_PICK_HEAD check and `cherry-pick --continue`.

### Fix Focus Areas
- webhook_server/libs/handlers/runner_handler.py[1280-1289]

### Proposed fix
- Replace `git add -u` with `git add -A` (or `git add --all`) so new files created/kept during conflict resolution are staged.
- Keep the existing error handling, but ensure the staging step truly stages *everything* the AI resolved.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. Git+SSH npm deps pinned ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new sidecar build stage runs npm ci, but sidecar-helper/package-lock.json pins transitive
dependencies to git+ssh://git@github.com/..., which requires SSH credentials during the Docker
build and can fail in CI/build environments that don’t provide SSH keys/agent forwarding.
Code

Dockerfile[R1-8]

+# Sidecar build stage
+FROM node:22-slim AS sidecar-builder
+WORKDIR /sidecar
+COPY sidecar-helper/package.json sidecar-helper/package-lock.json* ./
+RUN npm ci
+COPY sidecar-helper/ .
+RUN npx tsc
+RUN npm prune --omit=dev
Relevance

⭐⭐ Medium

No direct history on git+ssh npm deps; team does act on Docker build reliability issues (e.g., PR
#965).

PR-#965

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR introduces a new Docker build stage that executes npm ci, and the checked-in lockfile shows
pi-orchestrator-config and pi-vertex-claude resolved via git+ssh://git@github.com/..., which
requires SSH access during install.

Dockerfile[1-8]
sidecar-helper/package-lock.json[2716-2737]
sidecar-helper/package-lock.json[1466-1479]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Docker sidecar build runs `npm ci`, but the lockfile contains `git+ssh://git@github.com/...` resolved URLs for transitive dependencies. This typically breaks container builds (and reproducibility) unless the build environment is explicitly configured with SSH credentials and git/ssh tooling.

## Issue Context
`npm ci` strictly follows the lockfile; `git+ssh` URLs require an SSH key and an SSH client.

## Fix Focus Areas
- Dockerfile[1-8]
- sidecar-helper/package-lock.json[2716-2737]

## Recommended fix
- Regenerate `sidecar-helper/package-lock.json` in a clean environment so GitHub dependencies resolve via `git+https://...` (or npm registry tarballs) rather than `git+ssh://...`.
- If SSH-based deps are truly required (e.g., private repos), update the sidecar-builder stage to install `git` + `openssh-client` and use an explicit, secure SSH provisioning mechanism during build (e.g., BuildKit SSH mount), documenting it in build instructions.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. Arbitrary file read via diff ✓ Resolved 🐞 Bug ⛨ Security
Description
run_git_command() forwards unfiltered git diff arguments, allowing `git diff --no-index
/path/to/secret /dev/null` to return arbitrary filesystem contents if the endpoint is reachable or
the AI is prompt-injected into invoking it. This breaks the intended “read-only git tooling”
boundary and can leak secrets from the container/mounted volumes.
Code

webhook_server/web/git_tools.py[R35-55]

+    parts = shlex.split(request.args)
+    if not parts:
+        raise HTTPException(status_code=400, detail="Empty git command")
+
+    subcommand = parts[0]
+    if subcommand not in ALLOWED_GIT_COMMANDS:
+        raise HTTPException(
+            status_code=403,
+            detail=f"Git subcommand '{subcommand}' not allowed. Allowed: {', '.join(sorted(ALLOWED_GIT_COMMANDS))}",
+        )
+
+    # Build argument list — no shell interpolation
+    cmd_args = ["git", "-C", request.cwd, *parts]
+    proc: asyncio.subprocess.Process | None = None
+    try:
+        proc = await asyncio.create_subprocess_exec(
+            *cmd_args,
+            stdout=asyncio.subprocess.PIPE,
+            stderr=asyncio.subprocess.PIPE,
+        )
+        stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=30)
Relevance

⭐⭐ Medium

No historical evidence on filtering git diff flags; team does accept internal-endpoint security
hardening (PR #982, #1109).

PR-#982
PR-#1109

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The endpoint parses request.args and passes it directly to git without filtering dangerous
diff flags, and the runner builds AI custom tools that let the AI provide that args string.

webhook_server/web/git_tools.py[32-60]
webhook_server/libs/handlers/runner_handler.py[65-100]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The internal `/internal/git-tools/run` endpoint allowlists only the git *subcommand* (`diff`, `log`, etc.) but does not restrict subcommand arguments. For `git diff`, the `--no-index` flag enables diffing arbitrary filesystem paths (including absolute paths), which can leak secrets.

## Issue Context
- The endpoint is used by pi-sidecar HTTP-backed custom tools.
- The AI can supply the `args` string (via the custom tool schema), so prompt injection or accidental misuse can trigger dangerous git invocations.

## Fix Focus Areas
- webhook_server/web/git_tools.py[33-60]

### Recommended fix
1. Add per-subcommand argument validation, starting with `diff`:
  - Reject `--no-index` explicitly.
  - Consider rejecting absolute-path operands and `..` path traversal in path arguments after `--`.
2. Optionally narrow the allowed `diff` flags to a safe subset for your use cases (`--stat`, `--name-only`, specific rev ranges, and relative pathspecs).
3. Add a unit test proving `diff --no-index /etc/passwd /dev/null` (or any absolute path) is rejected with 403/400.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


14. run_git_command catches broad Exception 📘 Rule violation ≡ Correctness
Description
run_git_command() catches Exception and converts it to a success=false response, which can
silently hide unexpected programming/integration failures. This violates the requirement to catch
specific exception types (or log with full context and re-raise at true process boundaries).
Code

webhook_server/web/git_tools.py[R58-59]

+    except Exception as ex:
+        return GitCommandResponse(success=False, output=str(ex))
Relevance

⭐⭐ Medium

Broad Exception sometimes accepted for handler robustness, but usually with
logger.exception/re-raise; here it swallows errors.

PR-#1109
PR-#968
PR-#982

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 181390 disallows broad except Exception in non-boundary code paths unless it is
tightly justified and properly observed. The new endpoint handler catches Exception and returns a
normal response, suppressing unexpected failures.

Rule 181390: Catch specific exception types instead of broad Exception
webhook_server/web/git_tools.py[56-59]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`webhook_server/web/git_tools.py` uses a broad `except Exception as ex:` and returns `str(ex)`, which can suppress unexpected errors.

## Issue Context
This endpoint is invoked during AI sessions; unexpected exceptions should not be silently flattened into a generic response.

## Fix Focus Areas
- webhook_server/web/git_tools.py[56-59]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


15. Git-tools shell injection 🐞 Bug ⛨ Security
Description
run_git_command() validates only the first token of args but then interpolates the full
untrusted request.args into a shell string and executes it with create_subprocess_shell,
allowing ;/&& command injection after an allowed subcommand.
Code

webhook_server/web/git_tools.py[R35-55]

+    parts = shlex.split(request.args)
+    if not parts:
+        raise HTTPException(status_code=400, detail="Empty git command")
+
+    subcommand = parts[0]
+    if subcommand not in ALLOWED_GIT_COMMANDS:
+        raise HTTPException(
+            status_code=403,
+            detail=f"Git subcommand '{subcommand}' not allowed. Allowed: {', '.join(sorted(ALLOWED_GIT_COMMANDS))}",
+        )
+
+    cmd = f"git -C {shlex.quote(request.cwd)} {request.args}"
+    try:
+        proc = await asyncio.create_subprocess_shell(
+            cmd,
+            stdout=asyncio.subprocess.PIPE,
+            stderr=asyncio.subprocess.PIPE,
+        )
+        stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=30)
+        output = stdout.decode() if proc.returncode == 0 else stderr.decode()
+        return GitCommandResponse(success=proc.returncode == 0, output=output[:50000])
Relevance

⭐⭐ Medium

No direct historical reviews on subprocess_shell injection; only general subprocess
hardening/cleanup precedent found.

PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The endpoint uses shlex.split() only for the allowlist check, but still executes the raw
request.args through a shell, enabling injected shell metacharacters to be interpreted.

webhook_server/web/git_tools.py[35-55]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`/internal/git-tools/run` is intended to run read-only git commands, but it is currently vulnerable to shell command injection because it executes a string via `asyncio.create_subprocess_shell()` and appends `request.args` directly.

### Issue Context
The handler already parses `request.args` with `shlex.split()` to check the first token, but it then ignores the parsed list and executes the raw string.

### Fix Focus Areas
- webhook_server/web/git_tools.py[35-55]

### Implementation guidance
- Replace `create_subprocess_shell(cmd, ...)` with `create_subprocess_exec(*argv, ...)`.
- Build `argv` from the parsed `parts` (e.g., `argv = ["git", "-C", request.cwd, *parts]`).
- Keep the existing subcommand allowlist check, but apply it to `parts[0]` and only execute the `parts` list.
- Catch `asyncio.TimeoutError` from `wait_for` (or both `asyncio.TimeoutError` and `TimeoutError`) to be robust.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


16. Sidecar readiness not enforced 📎 Requirement gap ☼ Reliability
Description
entrypoint.sh polls the sidecar /health endpoint but still proceeds to start the main app even
if the sidecar never becomes ready, and it only logs a warning when the sidecar script is missing.
This violates the requirement to ensure pi-sidecar availability with a clear failure mode and can
leave the container running while degraded/unhealthy until the orchestrator intervenes.
Code

entrypoint.sh[R5-29]

+if [ -f "$APP_DIR/sidecar-helper/dist/server.js" ]; then
+    export SIDECAR_PORT="${SIDECAR_PORT:-9100}"
+    export SIDECAR_ACPX_EXTENSION_PATH="$APP_DIR/sidecar-helper/node_modules/@myk-org/pi-sidecar/node_modules/pi-orchestrator-config/extensions/acpx-provider/index.ts"
+    node "$APP_DIR/sidecar-helper/dist/server.js" &
+    SIDECAR_PID=$!
+    echo "[sidecar] Started Pi SDK sidecar (PID $SIDECAR_PID) on port $SIDECAR_PORT"
+
+    # Kill sidecar when main process exits
+    trap 'kill $SIDECAR_PID 2>/dev/null; wait $SIDECAR_PID 2>/dev/null' EXIT
+
+    # Monitor sidecar — if it dies, kill the main process too
+    # TERM trap prevents misleading "died" message on normal shutdown
+    (trap 'exit 0' TERM; while kill -0 $SIDECAR_PID 2>/dev/null; do sleep 5; done; echo "[sidecar] Sidecar died, shutting down container"; kill 1 2>/dev/null) &
+
+    # Wait for sidecar to be ready (up to 15s)
+    for i in $(seq 1 30); do
+        if curl -sf http://127.0.0.1:$SIDECAR_PORT/health > /dev/null 2>&1; then
+            echo "[sidecar] Health check passed"
+            break
+        fi
+        sleep 0.5
+    done
+else
+    echo "[sidecar] WARNING: sidecar-helper/dist/server.js not found, AI features will not be available"
+fi
Relevance

⭐⭐ Medium

No historical review evidence for sidecar readiness fail-fast behavior; entrypoint.sh is new (no
file history).

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 181410 requires runtime startup to ensure sidecar availability and to fail
explicitly when the sidecar is missing or unhealthy, but the script only warns if
sidecar-helper/dist/server.js is absent and its readiness loop breaks only on success without any
post-loop handling before exec uv run entrypoint.py if /health never succeeds. Additionally, the
Docker HEALTHCHECK marks the container unhealthy when the sidecar health endpoint is down, so
starting the main server without enforcing sidecar readiness can result in a container that is
"running" yet unhealthy.

Ensure pi-sidecar runtime availability and handle missing sidecar as a failure mode
entrypoint.sh[5-29]
entrypoint.sh[1-32]
Dockerfile[93-107]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`entrypoint.sh` does not enforce that pi-sidecar is present and healthy before starting the main process: it only logs a warning when `sidecar-helper/dist/server.js` is missing, and its `/health` readiness polling loop has no failure handling, so after the wait window it still starts the main app even if readiness was never achieved.

## Issue Context
Compliance (PR Compliance ID 181410) requires (1) runtime startup ensures sidecar availability and (2) missing/unhealthy sidecar is handled explicitly with a clear failure mode. Docker `HEALTHCHECK` also requires both the webhook server and the sidecar to be healthy, meaning the container can appear "running" while remaining unhealthy if the main process starts without a ready sidecar.

## Fix Focus Areas
- entrypoint.sh[5-32]
- Dockerfile[105-107]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

17. Unhandled JSON content-type 🐞 Bug ☼ Reliability
Description
handle_tool_request() only catches ValueError/TypeError from request.json(), so aiohttp
ContentType/HTTPBadRequest-style JSON parsing failures can escape and produce a non-JSON error
response. This breaks the apparent “always JSON” response contract of the tool server and can cause
clients to fail parsing error responses.
Code

webhook_server/web/tool_server.py[R70-71]

+    except (ValueError, TypeError) as ex:
+        return web.json_response({"detail": f"Invalid JSON: {ex}"}, status=400)
Relevance

⭐⭐⭐ High

Team often accepts hardening error handling/validation to avoid uncaught exceptions and improve
reliable responses (e.g., PRs #984, #982).

PR-#984
PR-#982
PR-#1109

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The handler currently formats invalid JSON errors only for ValueError/TypeError, while other
validation failures are consistently returned via JSON responses. If aiohttp raises a different
exception type for JSON/content-type errors, that path will bypass this JSON formatting and violate
the endpoint’s otherwise consistent JSON error response pattern.

webhook_server/web/tool_server.py[66-72]
webhook_server/web/tool_server.py[84-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`handle_tool_request()` wraps `await request.json()` with `except (ValueError, TypeError)` only. In aiohttp, some malformed requests (notably wrong/missing JSON Content-Type) raise aiohttp-specific HTTP exceptions rather than `ValueError`/`TypeError`, which can bypass this handler’s JSON error formatting and return a non-JSON error response.

### Issue Context
The rest of this endpoint consistently uses `web.json_response(...)` for error paths, implying JSON responses are part of the endpoint contract.

### Fix Focus Areas
- webhook_server/web/tool_server.py[66-83]

### Suggested fix
- Expand the exception handling around `request.json()` to also catch aiohttp’s JSON/content-type related exceptions (e.g., aiohttp `ContentTypeError` / `HTTPBadRequest` equivalents) and return `web.json_response(..., status=400)`.
- Keep the handler strict (avoid reverting to a blanket `except Exception`)—only include the specific aiohttp exception types that represent malformed requests.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


18. Unvalidated tool timeout ✓ Resolved 🐞 Bug ☼ Reliability
Description
webhook_server.web.tool_server.handle_tool_request() uses the request-provided "timeout" directly in
asyncio.wait_for() without type/range validati...

Comment thread entrypoint.sh
Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 7876be6

@myakove myakove force-pushed the fix/issue-1126-pi-sidecar-ai-cherry-pick branch from 7876be6 to ebe489d Compare June 20, 2026 11:45
@myakove myakove force-pushed the fix/issue-1126-pi-sidecar-ai-cherry-pick branch from ebe489d to b35be0b Compare June 20, 2026 11:52
Comment thread webhook_server/libs/handlers/runner_handler.py
Comment thread Dockerfile
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit b35be0b

@myakove

myakove commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Added pr_title parameter and included in prompt.

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Added verification instruction to prompt.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Changed staging command to include new files.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Skipped: By design: deliberate graceful degradation. AI features are optional. Docker HEALTHCHECK enforces both.

webhook_server/libs/handlers/runner_handler.py:1223 (qodo bug) — AI tools contradict prompt

Addressed: Removed Run git log/diff instructions. Updated system_prompt.

Dockerfile:93 (qodo bug) — Cross-OS node_modules copy

Skipped: False positive: all sidecar deps are pure JS/TS, no native bindings.

webhook_server/libs/handlers/runner_handler.py:1340 (qodo bug) — Diff verify ignores failure

Addressed: Added rc check for git diff. Logs warning and returns early on failure.

webhook_server/libs/handlers/runner_handler.py:1360 (qodo rule violation) — _verify_cherry_pick_scope catches Exception

Addressed: Changed except Exception to except (OSError, ValueError).

webhook_server/libs/handlers/runner_handler.py:1197 (qodo bug) — Untrusted prompt with bash

Addressed: Bash tool removed. AI uses read/edit/write/grep/find/ls only. Documented in AGENTS.md.

@qodo-code-review

Copy link
Copy Markdown

code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Added pr_title parameter and included in prompt.

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Added verification instruction to prompt.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Changed staging command to include new files.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Skipped: By design: deliberate graceful degradation. AI features are optional. Docker HEALTHCHECK enforces both.

webhook_server/libs/handlers/runner_handler.py:1223 (qodo bug) — AI tools contradict prompt

Addressed: Removed Run git log/diff instructions. Updated system_prompt.

Dockerfile:93 (qodo bug) — Cross-OS node_modules copy

Skipped: False positive: all sidecar deps are pure JS/TS, no native bindings.

webhook_server/libs/handlers/runner_handler.py:1340 (qodo bug) — Diff verify ignores failure

Addressed: Added rc check for git diff. Logs warning and returns early on failure.

webhook_server/libs/handlers/runner_handler.py:1360 (qodo rule violation) — _verify_cherry_pick_scope catches Exception

Addressed: Changed except Exception to except (OSError, ValueError).

webhook_server/libs/handlers/runner_handler.py:1197 (qodo bug) — Untrusted prompt with bash

Addressed: Bash tool removed. AI uses read/edit/write/grep/find/ls only. Documented in AGENTS.md.

Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: pr_title, diff verification, and safer tool access are all in place.
  • The cherry-pick path now stages new files and fails more safely on verification errors.
  • The sidecar startup/healthcheck changes make the deployment model explicit.

A couple of intentional skips to keep in mind:

  • finding 4: leaving sidecar readiness as best-effort is reasonable if AI is optional, since the container healthcheck still covers it.
  • finding 6: the cross-OS node_modules copy is fine for now if the sidecar stays pure JS, but it’s worth revisiting if native deps ever get added.

So my read is: no remaining blocking issues from the review set, unless you want to harden the optional sidecar startup behavior further.

Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 72c8e5d

@myakove

myakove commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Already fixed in commit 72c8e5d: pr_title parameter added to _resolve_cherry_pick_with_ai() and included in prompt.

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in commit 72c8e5d: verification instruction added to prompt.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in commit 72c8e5d: changed staging to include new files.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Skipped: By design: deliberate graceful degradation. AI features are optional. Docker HEALTHCHECK enforces both being healthy. Monitor subshell kills container if sidecar dies.

webhook_server/libs/handlers/runner_handler.py:1254 (qodo bug) — Stat-only commit context

Addressed: Fixed: changed verification instruction to reference reading resolved files instead of comparing against stat-only context.

webhook_server/libs/handlers/runner_handler.py:1340 (qodo bug) — Diff verify ignores failure

Addressed: Already fixed in commit 72c8e5d: added rc check, logs warning and returns early on failure.

webhook_server/libs/handlers/runner_handler.py:1360 (qodo rule violation) — _verify_cherry_pick_scope catches Exception

Addressed: Already fixed in commit 72c8e5d: changed to except (OSError, ValueError).

Dockerfile:93 (qodo bug) — Cross-OS node_modules copy

Skipped: False positive: all sidecar deps are pure JS/TS, no native bindings. Checked package-lock.json for node-gyp/prebuild/napi — zero matches.

webhook_server/libs/handlers/runner_handler.py:1197 (qodo bug) — Untrusted prompt with bash

Addressed: Already fixed in commit 72c8e5d: bash tool removed. AI uses read/edit/write/grep/find/ls only.

myakove added 11 commits June 23, 2026 14:38
- Remove git command instructions from AI prompt (no bash access)
- Update system_prompt to reference file reading/editing tools
- Add PR title to cherry-pick conflict resolution prompt
- Add diff verification instruction to prompt
- Change git add -u to git add -A (stage new files)
- Check run_command rc in _verify_cherry_pick_scope
- Narrow exception from Exception to (OSError, ValueError)
- Document prompt injection risk mitigation in AGENTS.md
Change cherry-pick prompt verification from comparing against stat-only
context to reading resolved files directly — achievable with available
read/edit tools.
- Add internal /internal/git-tools/run endpoint with read-only allowlist
- Build custom tools (git_diff, git_log, git_show, git_status) for pi-sidecar
- Conventional title: uses git_diff + git_log custom tools (no builtin tools)
- Cherry-pick resolution: builtin file tools + custom git tools
- No bash access anywhere — all git operations via restricted HTTP endpoint
- Add 20 tests for git tools endpoint and helper
- Fix shell injection: create_subprocess_shell → create_subprocess_exec
- Fix timeout subprocess leak: kill + wait on timeout
- Narrow exception: Exception → OSError
- Read server port from config instead of hardcoding 5000
- Handle wildcard mode in AI title regex extraction
- Add security comment for internal git-tools endpoint
- Update test mocks for subprocess_exec
- Add sidecar healthcheck before AI calls
- Add localhost-only middleware for /internal/ endpoints
- Log error when sidecar fails readiness check
- Cache server port in RunnerHandler (no blocking Config read)
- Add git tool instructions to cherry-pick prompt
- Replace FastAPI router with standalone aiohttp server in daemon thread
- Own event loop — no contention with main webhook server during CI checks
- Binds to 127.0.0.1:5001 (localhost-only, no middleware needed)
- Custom tools now point to port 5001
- Add aiohttp dependency
- 23 tests rewritten for aiohttp test client
- Replace git-specific server with generic tool registry
- ToolDef dataclass: command_prefix, timeout, blocked_flags, success_exit_codes
- Callers select which tools AI sees per session
- Easy to add new tools — one registry entry
Explicitly explain conflict marker semantics (HEAD=target, >>>=cherry-picked).
Add concrete rules: keep new methods, use cherry-picked modifications.
Prohibit keeping HEAD version — defeats cherry-pick purpose.
- Narrow exception handling (ValueError/TypeError instead of Exception)
- Validate and clamp tool timeout (1-300s)
- Fix conflict marker explanation in cherry-pick prompt
- Honest startup log (starting vs started)
@myakove-bot

Copy link
Copy Markdown
Collaborator

Clean rebase detected — no code changes compared to previous head (6a45a2b).
The following labels were preserved: commented-qodo-code-review[bot].

Comment thread webhook_server/web/tool_server.py
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 603ee07

Broad JSON catch, type validation for cwd/args
@myakove

myakove commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: By design: simplified prompt proven effective — E2E tests show 100% element preservation across 3 different complex conflict scenarios (DataValidator 9/9, ConfigManager 10/10, DataProcessor 9/9). The AI is an expert and performs better with concise context than verbose instructions. Updated issue #1126 spec to document this design decision.

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: File deleted — replaced by tool_server.py with all fixes.

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed fix: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: File deleted — replaced by tool_server.py with all fixes.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: File deleted — replaced by tool_server.py with all fixes.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits.

webhook_server/web/tool_server.py:73 (qodo bug) — Tool request types unchecked

Addressed: Fixed in commit 10eb56b: added isinstance(str) validation for cwd and args fields.

@qodo-code-review

Copy link
Copy Markdown

code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: By design: simplified prompt proven effective — E2E tests show 100% element preservation across 3 different complex conflict scenarios (DataValidator 9/9, ConfigManager 10/10, DataProcessor 9/9). The AI is an expert and performs better with concise context than verbose instructions. Updated issue #1126 spec to document this design decision.

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: File deleted — replaced by tool_server.py with all fixes.

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed fix: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: File deleted — replaced by tool_server.py with all fixes.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: File deleted — replaced by tool_server.py with all fixes.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits.

webhook_server/web/tool_server.py:73 (qodo bug) — Tool request types unchecked

Addressed: Fixed in commit 10eb56b: added isinstance(str) validation for cwd and args fields.

Thanks — those reviewed comments have been marked addressed in the PR discussion.

What that means

  • The cited items are either already fixed, intentionally changed by design, or replaced by the new tool_server.py flow.
  • I don’t see anything in that bot message that needs further action on my side.

Still-open Qodo findings in the current index

The remaining active items are findings 1, 5, 11, 12, 13, 14, 15, 16, 18, 21, 25, 30, 31, 35, 36, 37, 38, 41, 42, 43, 44, 45, 47, 48.

If you want, I can help triage any of those next.

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 10eb56b

@myakove

myakove commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: File deleted — replaced by tool_server.py.

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: File deleted — replaced by tool_server.py.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: File deleted — replaced by tool_server.py.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Fixed in commit 10eb56b: broadened to except Exception at HTTP boundary for JSON parsing.

@qodo-code-review

Copy link
Copy Markdown

code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: File deleted — replaced by tool_server.py.

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: File deleted — replaced by tool_server.py.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: File deleted — replaced by tool_server.py.

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits. Qodo confirmed in replies.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Fixed in commit 10eb56b: broadened to except Exception at HTTP boundary for JSON parsing.

Yes — the listed review comments look addressed in this patch.

  • webhook_server/web/git_tools.py was removed and replaced by webhook_server/web/tool_server.py, so the old localhost/shell-injection issues are no longer present there.
  • The cherry-pick AI flow now includes the PR title, commit/diff context, and post-resolution scope verification.
  • New files are staged with git add -A before finalizing the cherry-pick.
  • entrypoint.sh now waits for the sidecar health check at startup.
  • The JSON parsing path in tool_server.py now fails safely at the HTTP boundary.

If you want, I can also review the remaining active findings still open in the index.

@myakove

myakove commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Qodo confirmed: "Thanks — those reviewed comments have been marked addressed in the PR discussion..."

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: Qodo confirmed: "Thanks — those decisions look consistent with the current patch.

  • The localhos..."

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: Qodo confirmed: "Understood — the reviewed items are either addressed or intentionally skipped.

..."

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Already fixed in previous commits.

@qodo-code-review

Copy link
Copy Markdown

code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Qodo confirmed: "Thanks — those reviewed comments have been marked addressed in the PR discussion..."

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: Qodo confirmed: "Thanks — those decisions look consistent with the current patch.

  • The localhos..."

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: Qodo confirmed: "Understood — the reviewed items are either addressed or intentionally skipped.

..."

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Already fixed in previous commits.

Thanks — that set of review comments is now covered.

  • The items marked Addressed are consistent with the current patch.
  • The ones marked Already fixed were resolved in earlier commits.

So for this batch, there doesn’t appear to be anything left to action. If you want, I can also help triage the remaining active findings in the PR.

@myakove

myakove commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Qodo confirmed: "Thanks — those reviewed comments have been marked addressed in the PR discussion..."

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: Qodo confirmed: "Thanks — those decisions look consistent with the current patch.

  • The localhos..."

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: Qodo confirmed: "Understood — the reviewed items are either addressed or intentionally skipped.

..."

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Already fixed in previous commits.

@qodo-code-review

Copy link
Copy Markdown

code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Qodo confirmed: "Thanks — those reviewed comments have been marked addressed in the PR discussion..."

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: Qodo confirmed: "Thanks — those decisions look consistent with the current patch.

  • The localhos..."

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed in previous commits.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: Already fixed in previous commits.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: Qodo confirmed: "Understood — the reviewed items are either addressed or intentionally skipped.

..."

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed in previous commits.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Already fixed in previous commits.

Thanks — those reviewed comments are now marked as addressed.

A few of the remaining open items in the PR are still active outside that list, for example finding 11, finding 12, finding 21, finding 25, finding 30, finding 31, finding 35, finding 36, finding 37, finding 38, finding 41, finding 42, finding 43, and finding 44.

If you want, I can help triage or fix any of those next.

@myakove

myakove commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator Author

@qodo-code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Qodo confirmed: "Thanks — those reviewed comments have been marked addressed in the PR discussion..."

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: Qodo confirmed: "Thanks — those decisions look consistent with the current patch.

  • The localhos..."

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: Already fixed.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: Qodo confirmed: "Understood — the reviewed items are either addressed or intentionally skipped.

..."

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Already fixed.

@qodo-code-review

Copy link
Copy Markdown

code-review[bot]

The following review comments were reviewed and a decision was made:

webhook_server/libs/handlers/runner_handler.py:1285 (qodo requirement gap) — _resolve_cherry_pick_with_ai prompt vague

Addressed: Qodo confirmed: "Thanks — those reviewed comments have been marked addressed in the PR discussion..."

webhook_server/web/git_tools.py:30 (qodo bug) — Localhost check fails open

Addressed: Qodo confirmed: "Thanks — those decisions look consistent with the current patch.

  • The localhos..."

webhook_server/libs/handlers/runner_handler.py:1229 (qodo requirement gap) — Prompt missing PR title

Addressed: Qodo confirmed: "Overall, this looks in good shape.

  • The prompt / AI-flow gaps are addressed: `..."

webhook_server/libs/handlers/runner_handler.py:1237 (qodo requirement gap) — Prompt missing diff verification

Addressed: Already fixed.

webhook_server/libs/handlers/runner_handler.py:1280 (qodo bug) — New files not staged

Addressed: Already fixed.

webhook_server/web/git_tools.py:58 (qodo rule violation) — run_git_command catches broad Exception

Addressed: Already fixed.

webhook_server/web/git_tools.py:35 (qodo bug) — Git-tools shell injection

Addressed: Qodo confirmed: "Understood — the reviewed items are either addressed or intentionally skipped.

..."

entrypoint.sh:5 (qodo requirement gap) — Sidecar readiness not enforced

Addressed: Already fixed.

webhook_server/web/tool_server.py:70 (qodo bug) — Unhandled JSON content-type

Addressed: Already fixed.

Thanks — those reviewed comments have been marked addressed in the PR discussion.

  • The items you listed are no longer open concerns.
  • The remaining active findings are separate and still need attention if you want to continue the review.

If you want, I can also summarize the remaining active findings by risk level.

@myakove-bot

Copy link
Copy Markdown
Collaborator

New container for ghcr.io/myk-org/github-webhook-server:latest published

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: Migrate to pi-sidecar and improve AI cherry-pick conflict resolution

2 participants